/* do not edit automatically generated by mc from mcComp.  */
/* Copyright (C) 2015-2023 Free Software Foundation, Inc.
   This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with gm2; see the file COPYING.  If not, write to the Free Software
Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "Gmcrts.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _mcComp_H
#define _mcComp_C

#   include "GFIO.h"
#   include "Glibc.h"
#   include "Gdecl.h"
#   include "GsymbolKey.h"
#   include "GSYSTEM.h"
#   include "GmcReserved.h"
#   include "GmcSearch.h"
#   include "GmcLexBuf.h"
#   include "GmcFileName.h"
#   include "GmcPreprocess.h"
#   include "GFormatStrings.h"
#   include "Gmcflex.h"
#   include "Gmcp1.h"
#   include "Gmcp2.h"
#   include "Gmcp3.h"
#   include "Gmcp4.h"
#   include "Gmcp5.h"
#   include "GmcComment.h"
#   include "GmcError.h"
#   include "GnameKey.h"
#   include "GmcPrintf.h"
#   include "GmcQuiet.h"
#   include "GDynamicStrings.h"
#   include "GmcOptions.h"

#   define Debugging false
typedef struct mcComp_parserFunction_p mcComp_parserFunction;

typedef struct mcComp_openFunction_p mcComp_openFunction;

typedef bool (*mcComp_parserFunction_t) (void);
struct mcComp_parserFunction_p { mcComp_parserFunction_t proc; };

typedef bool (*mcComp_openFunction_t) (decl_node, bool);
struct mcComp_openFunction_p { mcComp_openFunction_t proc; };

static unsigned int currentPass;

/*
   compile - check, s, is non NIL before calling doCompile.
*/

extern "C" void mcComp_compile (DynamicStrings_String s);

/*
   getPassNo - return the pass no.
*/

extern "C" unsigned int mcComp_getPassNo (void);

/*
   doCompile - translate file, s, using a 6 pass technique.
*/

static void doCompile (DynamicStrings_String s);

/*
   examineCompilationUnit - opens the source file to obtain the module name and kind of module.
*/

static decl_node examineCompilationUnit (void);

/*
   peepInto - peeps into source, s, and initializes a definition/implementation or
              program module accordingly.
*/

static decl_node peepInto (DynamicStrings_String s);

/*
   initParser - returns the node of the module found in the source file.
*/

static decl_node initParser (DynamicStrings_String s);

/*
   p1 - wrap the pass procedure with the correct parameter values.
*/

static void p1 (decl_node n);

/*
   p2 - wrap the pass procedure with the correct parameter values.
*/

static void p2 (decl_node n);

/*
   p3 - wrap the pass procedure with the correct parameter values.
*/

static void p3 (decl_node n);

/*
   p4 - wrap the pass procedure with the correct parameter values.
*/

static void p4 (decl_node n);

/*
   p5 - wrap the pass procedure with the correct parameter values.
*/

static void p5 (decl_node n);

/*
   doOpen -
*/

static bool doOpen (decl_node n, DynamicStrings_String symName, DynamicStrings_String fileName, bool exitOnFailure);

/*
   openDef - try and open the definition module source file.
             Returns true/false if successful/unsuccessful or
             exitOnFailure.
*/

static bool openDef (decl_node n, bool exitOnFailure);

/*
   openMod - try and open the implementation/program module source file.
             Returns true/false if successful/unsuccessful or
             exitOnFailure.
*/

static bool openMod (decl_node n, bool exitOnFailure);

/*
   pass -
*/

static void pass (unsigned int no, decl_node n, mcComp_parserFunction f, decl_isNodeF isnode, mcComp_openFunction open);

/*
   doPass -
*/

static void doPass (bool parseDefs, bool parseMain, unsigned int no, symbolKey_performOperation p, const char *desc_, unsigned int _desc_high);

/*
   setToPassNo -
*/

static void setToPassNo (unsigned int n);

/*
   init - initialise data structures for this module.
*/

static void init (void);


/*
   doCompile - translate file, s, using a 6 pass technique.
*/

static void doCompile (DynamicStrings_String s)
{
  decl_node n;

  n = initParser (s);
  doPass (true, true, 1, (symbolKey_performOperation) {(symbolKey_performOperation_t) p1}, (const char *) "lexical analysis, modules, root decls and C preprocessor", 56);
  doPass (true, true, 2, (symbolKey_performOperation) {(symbolKey_performOperation_t) p2}, (const char *) "[all modules] type equivalence and enumeration types", 52);
  doPass (true, true, 3, (symbolKey_performOperation) {(symbolKey_performOperation_t) p3}, (const char *) "[all modules] import lists, types, variables and procedure declarations", 71);
  doPass (true, true, 4, (symbolKey_performOperation) {(symbolKey_performOperation_t) p4}, (const char *) "[all modules] constant expressions", 34);
  if (! (decl_isDef (n)))
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (decl_isImp (n))
        {
          mcQuiet_qprintf0 ((const char *) "Parse implementation module\\n", 29);
          doPass (false, true, 5, (symbolKey_performOperation) {(symbolKey_performOperation_t) p5}, (const char *) "[implementation module] build code tree for all procedures and module initializations", 85);
        }
      else
        {
          mcQuiet_qprintf0 ((const char *) "Parse program module\\n", 22);
          doPass (false, true, 5, (symbolKey_performOperation) {(symbolKey_performOperation_t) p5}, (const char *) "[program module] build code tree for all procedures and module initializations", 78);
        }
    }
  mcQuiet_qprintf0 ((const char *) "walk tree converting it to C/C++\\n", 34);
  decl_out ();
}


/*
   examineCompilationUnit - opens the source file to obtain the module name and kind of module.
*/

static decl_node examineCompilationUnit (void)
{
  /* stop if we see eof, ';' or '['  */
  while (((mcLexBuf_currenttoken != mcReserved_eoftok) && (mcLexBuf_currenttoken != mcReserved_semicolontok)) && (mcLexBuf_currenttoken != mcReserved_lsbratok))
    {
      if (mcLexBuf_currenttoken == mcReserved_definitiontok)
        {
          mcLexBuf_getToken ();
          if (mcLexBuf_currenttoken == mcReserved_moduletok)
            {
              /* avoid dangling else.  */
              mcLexBuf_getToken ();
              if (mcLexBuf_currenttoken == mcReserved_fortok)
                {
                  mcLexBuf_getToken ();
                  if (mcLexBuf_currenttoken == mcReserved_stringtok)
                    {
                      mcLexBuf_getToken ();
                    }
                  else
                    {
                      mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "expecting language string after FOR keyword", 43)));
                      libc_exit (1);
                    }
                }
              if (mcLexBuf_currenttoken == mcReserved_identtok)
                {
                  return decl_lookupDef (nameKey_makekey (mcLexBuf_currentstring));
                }
            }
          else
            {
              mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "MODULE missing after DEFINITION keyword", 39)));
            }
        }
      else if (mcLexBuf_currenttoken == mcReserved_implementationtok)
        {
          /* avoid dangling else.  */
          mcLexBuf_getToken ();
          if (mcLexBuf_currenttoken == mcReserved_moduletok)
            {
              /* avoid dangling else.  */
              mcLexBuf_getToken ();
              if (mcLexBuf_currenttoken == mcReserved_identtok)
                {
                  return decl_lookupImp (nameKey_makekey (mcLexBuf_currentstring));
                }
            }
          else
            {
              mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "MODULE missing after IMPLEMENTATION keyword", 43)));
            }
        }
      else if (mcLexBuf_currenttoken == mcReserved_moduletok)
        {
          /* avoid dangling else.  */
          mcLexBuf_getToken ();
          if (mcLexBuf_currenttoken == mcReserved_identtok)
            {
              return decl_lookupModule (nameKey_makekey (mcLexBuf_currentstring));
            }
        }
      mcLexBuf_getToken ();
    }
  mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "failed to find module name", 26)));
  libc_exit (1);
  ReturnException ("../../gcc-read-write/gcc/m2/mc/mcComp.def", 20, 1);
  __builtin_unreachable ();
}


/*
   peepInto - peeps into source, s, and initializes a definition/implementation or
              program module accordingly.
*/

static decl_node peepInto (DynamicStrings_String s)
{
  decl_node n;
  DynamicStrings_String fileName;

  fileName = mcPreprocess_preprocessModule (s);
  if (mcLexBuf_openSource (fileName))
    {
      n = examineCompilationUnit ();
      decl_setSource (n, nameKey_makekey (DynamicStrings_string (fileName)));
      decl_setMainModule (n);
      mcLexBuf_closeSource ();
      mcLexBuf_reInitialize ();
      return n;
    }
  else
    {
      mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to open %s\\n", 19, (const unsigned char *) &s, (sizeof (s)-1));
      libc_exit (1);
    }
  ReturnException ("../../gcc-read-write/gcc/m2/mc/mcComp.def", 20, 1);
  __builtin_unreachable ();
}


/*
   initParser - returns the node of the module found in the source file.
*/

static decl_node initParser (DynamicStrings_String s)
{
  mcQuiet_qprintf1 ((const char *) "Compiling: %s\\n", 15, (const unsigned char *) &s, (sizeof (s)-1));
  return peepInto (s);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   p1 - wrap the pass procedure with the correct parameter values.
*/

static void p1 (decl_node n)
{
  if (decl_isDef (n))
    {
      /* avoid dangling else.  */
      pass (1, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp1_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef});
      if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ()))
        {
          pass (1, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp1_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
        }
    }
  else
    {
      pass (1, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp1_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
    }
}


/*
   p2 - wrap the pass procedure with the correct parameter values.
*/

static void p2 (decl_node n)
{
  if (decl_isDef (n))
    {
      /* avoid dangling else.  */
      pass (2, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp2_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef});
      if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ()))
        {
          pass (2, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp2_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
        }
    }
  else
    {
      pass (2, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp2_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
    }
}


/*
   p3 - wrap the pass procedure with the correct parameter values.
*/

static void p3 (decl_node n)
{
  if (decl_isDef (n))
    {
      /* avoid dangling else.  */
      pass (3, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp3_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef});
      if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ()))
        {
          pass (3, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp3_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
        }
    }
  else
    {
      pass (3, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp3_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
    }
}


/*
   p4 - wrap the pass procedure with the correct parameter values.
*/

static void p4 (decl_node n)
{
  if (decl_isDef (n))
    {
      /* avoid dangling else.  */
      pass (4, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp4_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef});
      if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ()))
        {
          pass (4, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp4_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
        }
    }
  else
    {
      pass (4, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp4_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
    }
}


/*
   p5 - wrap the pass procedure with the correct parameter values.
*/

static void p5 (decl_node n)
{
  pass (5, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp5_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod});
}


/*
   doOpen -
*/

static bool doOpen (decl_node n, DynamicStrings_String symName, DynamicStrings_String fileName, bool exitOnFailure)
{
  DynamicStrings_String postProcessed;

  mcQuiet_qprintf2 ((const char *) "   Module %-20s : %s\\n", 22, (const unsigned char *) &symName, (sizeof (symName)-1), (const unsigned char *) &fileName, (sizeof (fileName)-1));
  postProcessed = mcPreprocess_preprocessModule (fileName);
  decl_setSource (n, nameKey_makekey (DynamicStrings_string (postProcessed)));
  decl_setCurrentModule (n);
  if (mcLexBuf_openSource (postProcessed))
    {
      return true;
    }
  mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to open %s\\n", 19, (const unsigned char *) &fileName, (sizeof (fileName)-1));
  if (exitOnFailure)
    {
      libc_exit (1);
    }
  return false;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   openDef - try and open the definition module source file.
             Returns true/false if successful/unsuccessful or
             exitOnFailure.
*/

static bool openDef (decl_node n, bool exitOnFailure)
{
  nameKey_Name sourceName;
  DynamicStrings_String symName;
  DynamicStrings_String fileName;

  sourceName = decl_getSource (n);
  symName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (decl_getSymName (n)));
  if (sourceName == nameKey_NulName)
    {
      /* avoid dangling else.  */
      if (! (mcSearch_findSourceDefFile (symName, &fileName)))
        {
          mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to find definition module %s.def\\n", 41, (const unsigned char *) &symName, (sizeof (symName)-1));
          if (exitOnFailure)
            {
              libc_exit (1);
            }
        }
    }
  else
    {
      fileName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (sourceName));
    }
  return doOpen (n, symName, fileName, exitOnFailure);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   openMod - try and open the implementation/program module source file.
             Returns true/false if successful/unsuccessful or
             exitOnFailure.
*/

static bool openMod (decl_node n, bool exitOnFailure)
{
  nameKey_Name sourceName;
  DynamicStrings_String symName;
  DynamicStrings_String fileName;

  sourceName = decl_getSource (n);
  symName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (decl_getSymName (n)));
  if (sourceName == nameKey_NulName)
    {
      /* avoid dangling else.  */
      if (! (mcSearch_findSourceModFile (symName, &fileName)))
        {
          if (decl_isImp (n))
            {
              mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to find implementation module %s.mod\\n", 45, (const unsigned char *) &symName, (sizeof (symName)-1));
            }
          else
            {
              mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to find program module %s.mod\\n", 38, (const unsigned char *) &symName, (sizeof (symName)-1));
            }
          if (exitOnFailure)
            {
              libc_exit (1);
            }
        }
    }
  else
    {
      fileName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (sourceName));
    }
  return doOpen (n, symName, fileName, exitOnFailure);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   pass -
*/

static void pass (unsigned int no, decl_node n, mcComp_parserFunction f, decl_isNodeF isnode, mcComp_openFunction open)
{
  if (((*isnode.proc) (n)) && (! (decl_isVisited (n))))
    {
      decl_setVisited (n);
      if ((*open.proc) (n, true))
        {
          if (! ((*f.proc) ()))
            {
              mcError_writeFormat0 ((const char *) "compilation failed", 18);
              mcLexBuf_closeSource ();
              return ;
            }
          mcLexBuf_closeSource ();
        }
    }
}


/*
   doPass -
*/

static void doPass (bool parseDefs, bool parseMain, unsigned int no, symbolKey_performOperation p, const char *desc_, unsigned int _desc_high)
{
  DynamicStrings_String descs;
  char desc[_desc_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (desc, desc_, _desc_high+1);

  setToPassNo (no);
  descs = DynamicStrings_InitString ((const char *) desc, _desc_high);
  mcQuiet_qprintf2 ((const char *) "Pass %d: %s\\n", 13, (const unsigned char *) &no, (sizeof (no)-1), (const unsigned char *) &descs, (sizeof (descs)-1));
  decl_foreachDefModuleDo ((symbolKey_performOperation) {(symbolKey_performOperation_t) decl_unsetVisited});
  decl_foreachModModuleDo ((symbolKey_performOperation) {(symbolKey_performOperation_t) decl_unsetVisited});
  if (parseMain)
    {
      decl_unsetVisited (decl_getMainModule ());
      if (parseDefs && (decl_isImp (decl_getMainModule ())))
        {
          /* we need to parse the definition module of a corresponding implementation module.  */
          (*p.proc) (reinterpret_cast<void *> (decl_lookupDef (decl_getSymName (decl_getMainModule ()))));
        }
      (*p.proc) (reinterpret_cast<void *> (decl_getMainModule ()));
    }
  if (parseDefs)
    {
      decl_foreachDefModuleDo (p);
    }
  mcError_flushWarnings ();
  mcError_flushErrors ();
  setToPassNo (0);
}


/*
   setToPassNo -
*/

static void setToPassNo (unsigned int n)
{
  currentPass = n;
}


/*
   init - initialise data structures for this module.
*/

static void init (void)
{
  setToPassNo (0);
}


/*
   compile - check, s, is non NIL before calling doCompile.
*/

extern "C" void mcComp_compile (DynamicStrings_String s)
{
  if (s != NULL)
    {
      doCompile (s);
    }
}


/*
   getPassNo - return the pass no.
*/

extern "C" unsigned int mcComp_getPassNo (void)
{
  return currentPass;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_mcComp_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
  init ();
}

extern "C" void _M2_mcComp_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
